package cn.tianwt.proxy.http.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import cn.tianwt.proxy.http.utils.Configs;
import cn.tianwt.proxy.http.utils.ThreadPoolManager;

public class Worker extends Thread {
	//http协议内容中的CRLF
	
	private final Socket client;
	
	private  int mDefaultServerPort = 80;
	
	Worker(Socket client) {
		this.client = client;
	}
	@Override
	public void run() {
		//Web Server地址和端口号.
		String serverAddr = null;
		// 查看是否存在端口号,如果不存在使用默认端口号80
		int serverPort = mDefaultServerPort;
		
		try {
			// java1.7特性之TWR（TWR参考文档：http://m.blog.csdn.net/article/details?id=50901195 ）
			try (InputStream clientIs = client.getInputStream();
					OutputStream clientOs = client.getOutputStream();) {
				//默认只读取前100K,假定所有的头部都不超过100K就可以解析到Host头部.这块也是不好的地方
				
				int length = -1;
				
				byte[] data = new byte[1024*100];  
				length = clientIs.read(data);
				String clientInput = new String(data, 0, length);
				// 获取请求行,根据HTTP协议规范,第一行为请求行.
				String reqLine = clientInput.substring(0, clientInput.indexOf(Configs.CRLF));
				if(reqLine == null) {
					client.close();
				}
				
				authUser();
				
				System.out.println(reqLine);
				// 开始解析Web Server URL 和 端口号
				// 根据HTTP协议规范,请求行中包含: Method Request-URL
				// HTTP-Version,字段间以空格符隔开,并且末尾添加换行
				String[] params = reqLine.split(" ");
				String reqMethod = params[0];
				String reqUrl = params[1];
				String serverUrl = getServerURL(clientInput, reqUrl);
				// 开始获取Web Server地址和端口号.
				serverAddr = serverUrl;
				if (serverUrl.indexOf(":") > 0) {
					serverAddr = serverUrl.substring(0, serverUrl.indexOf(":"));
					serverPort = Integer.parseInt(serverUrl.substring(serverUrl.indexOf(":") + 1));
				}
				// 接下来开始真正的代理转发逻辑.
				try (Socket server = new Socket(serverAddr, serverPort);
						InputStream serverIs = server.getInputStream();
						OutputStream serverOs = server.getOutputStream()) {
					System.out.println("local port is: " + server.getLocalPort());
					//判断是否是CONNECT方法
					if(reqMethod.equalsIgnoreCase("CONNECT")) {
						String proxyResponse = "HTTP/1.1 200 Connection Established" + Configs.CRLF +
													"Proxy-agent: Anyone-BlindProxyServer/1.0" 
													+ Configs.CRLF +
													Configs.CRLF;
						clientOs.write(proxyResponse.getBytes());
						clientOs.flush();
					} else {
						//其他的HTTP方法,将读取到的数据原封不动的发送到Server端.
						serverOs.write(data, 0, length);
						serverOs.flush();
					}
					transport(clientIs, clientOs, server, serverIs, serverOs);
				}
			}
		} catch (Exception e) {
			try {
				client.close();
			} catch (Exception e2) {
			}
			System.out.println("failed to connect to server[" + serverAddr +"] : [" + serverPort + "]...");
		}
	}
	private void authUser() {
		//可做407 用户身份验证，读取Proxy-Authorization header，这里省略
	}
	private void transport(InputStream clientIs, OutputStream clientOs, Socket server, InputStream serverIs,
			OutputStream serverOs) {
		while (!client.isInputShutdown() || !server.isInputShutdown()) {
			synchronized (this) {
				// 将客户端的输入流管道输入到server sock的输出流.
				//client to server.
				ThreadPoolManager.get().execute(new PipeThread(client, server, clientIs, serverOs));
				//server to clien.
				ThreadPoolManager.get().execute(new PipeThread(server, client, serverIs, clientOs));
			}
			try {
				Thread.sleep(2000);
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}
	private String getServerURL(String input, String reqUrl) {
		String serverUrl = null;
		//解析远端主机.
		if (reqUrl.startsWith("/")) {
			int location = 0;
			while((location = input.indexOf(Configs.CRLF)) > 0) {
				String header = input.substring(0, location);
				// 根据HTTP协议规范,如果请求行中使用相对路径,则Web Server主机由Host头部决定.
				// 需要注意HTTP协议规范中是大小写不敏感的,所以需要使用equalsIgnoreCase
				if (header.length() > 5 && header.substring(0, 5).equalsIgnoreCase("Host:")) {
					String host = header.substring("Host:".length(), header.length());
					serverUrl = host;
					break;
				}
				input = input.substring(location + Configs.CRLF.length());
			}
		} else {
			// 根据HTTP协议规范,如果请求行中使用绝对路径,则Web
			// Server主机是URL的一部分,且必须忽略Host头部.
			serverUrl = reqUrl;
		}
		// url: http://www.baidu.com/index.html
		if (serverUrl.indexOf("//") > 0) {
			serverUrl = serverUrl.substring(serverUrl.indexOf("//") + 2);
		}
		// 去除URL中的路径只保留域名: www.baidu.com/index.html
		if (serverUrl.indexOf("/") > 0) {
			serverUrl = serverUrl.substring(0, serverUrl.indexOf("/"));
		}
		return serverUrl;
	}
	public static Worker startHandle(Socket client) {
		Worker worker = new Worker(client);
		worker.start();
		return worker;
	}
}
